define([
    'dojo/_base/declare',
    'geomap/plugins/layers/CanvasLayer',
    'dojo/_base/config',
    'dojo/dom-construct',
    'esri/geometry/Point',
    'dojo/on',
], function (declare, CanvasLayer, config, domConstruct, Point, on) {
    return declare([CanvasLayer], {
        _refresh: function () {
            if (!this.visible) {
                return;
            }
            if (this.canvas && this.mapv) {
                if (this.map) {
                    this.setScale(this.map, this.canvas);
                }
                if (!this._elementVisible) {
                    return;
                }
                this.canvas.width = this.map.width;
                this.canvas.height = this.map.height;
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                this.canvasResolutionScale(this.ctx);

                var map_data = [];
                var data = this.data;
                for (var i = 0, len = data.length; i < len; i++) {
                    var item = data[i];
                    var point = new Point(item[this.lngFieldName], item[this.latFieldName]);
                    var p = this.map.toScreen(point);
                    map_data.push({
                        geometry: {
                            type: 'Point',
                            coordinates: [p.x, p.y],
                        },
                        count: item.count,
                    });
                }

                var DataSet = this.mapv.DataSet;
                var dataSet = new DataSet(map_data);
                var options = {
                    size: this.options.size || 40,
                    gradient: this.gradient || {
                        0.25: 'rgba(0,0,255,0.5)',
                        0.5: 'rgba(0,255,0,0.5)',
                        0.75: 'rgba(255,255,0,0.5)',
                        1.0: 'rgba(255,0,0,0.5)',
                    },
                    label: {
                        show: true,
                    },
                    draw: 'honeycomb',
                    maxOpacity: this.maxOpacity,
                };
                this.canvasDrawHoneycomb.draw.call(this, this.ctx, dataSet, options);
            }
        },
        canvasDrawHoneycomb: {
            draw: function draw(context, dataSet, options) {
                context.save();

                var data = dataSet.get();

                for (var key in options) {
                    context[key] = options[key];
                }

                var grids = {};

                var offset = options.offset || {
                    x: 10,
                    y: 10,
                };

                var r = options._size || options.size || 40;
                r = r / 2 / Math.sin(Math.PI / 3);
                var dx = r * 2 * Math.sin(Math.PI / 3);
                var dy = r * 1.5;

                var binsById = {};

                for (var i = 0; i < data.length; i++) {
                    var coordinates = data[i].geometry._coordinates || data[i].geometry.coordinates;
                    var py = (coordinates[1] - offset.y) / dy,
                        pj = Math.round(py),
                        px = (coordinates[0] - offset.x) / dx - (pj & 1 ? 0.5 : 0),
                        pi = Math.round(px),
                        py1 = py - pj;

                    if (Math.abs(py1) * 3 > 1) {
                        var px1 = px - pi,
                            pi2 = pi + (px < pi ? -1 : 1) / 2,
                            pj2 = pj + (py < pj ? -1 : 1),
                            px2 = px - pi2,
                            py2 = py - pj2;
                        if (px1 * px1 + py1 * py1 > px2 * px2 + py2 * py2)
                            (pi = pi2 + (pj & 1 ? 1 : -1) / 2), (pj = pj2);
                    }

                    var id = pi + '-' + pj,
                        bin = binsById[id];
                    if (bin) {
                        bin.push(data[i]);
                    } else {
                        bin = binsById[id] = [data[i]];
                        bin.i = pi;
                        bin.j = pj;
                        bin.x = (pi + (pj & 1 ? 1 / 2 : 0)) * dx;
                        bin.y = pj * dy;
                    }
                }
                var Intensity = this.mapv.utilDataRangeIntensity;
                var intensity = new Intensity({
                    max: options.max || 100,
                    maxSize: r,
                    gradient: options.gradient,
                });

                context.font = '12px Arial';
                for (var key in binsById) {
                    var item = binsById[key];

                    context.beginPath();

                    var x, y;
                    for (var j = 0; j < 6; j++) {
                        var radius = r;

                        var result = hex_corner(
                            {
                                x: item.x + offset.x,
                                y: item.y + offset.y,
                            },
                            radius,
                            j
                        );
                        x = result[0];
                        y = result[1];
                        context.lineTo(result[0], result[1]);
                    }
                    context.closePath();

                    var count = 0;
                    for (var i = 0; i < item.length; i++) {
                        item[i].count =
                            typeof item[i].count == 'string'
                                ? parseInt(item[i].count)
                                : item[i].count;
                        count += item[i].count || 1;
                    }

                    context.fillStyle = intensity.getColor(count);
                    context.fill();
                    if (options.strokeStyle || options.lineWidth) {
                        context.stroke();
                    }

                    if (options.label && options.label.show) {
                        context.fillStyle = '#fff';
                        context.textAlign = 'center';
                        context.fillText(count.toString(), x - dx / 2, y + 15);
                    }
                }

                context.restore();

                function hex_corner(center, size, i) {
                    var angle_deg = 60 * i + 30;
                    var angle_rad = (Math.PI / 180) * angle_deg;
                    return [
                        center.x + size * Math.cos(angle_rad),
                        center.y + size * Math.sin(angle_rad),
                    ];
                }
            },
        },
    });
});
